/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Rozvrh;

import GUIaVykreslovanie.PlatnoRozvrh;
import InformacnaStruktura.TypSalda;
import Sablony.Funkcia;
import Sablony.Pohlavie;
import Sablony.SiloveUlohy;
import Sablony.TypZamestnanca;
import Sablony.Zamestnanec;
import java.awt.Point;
import java.util.*;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *  Trieda, ktorá obsahuje informácie o rozvrhu mesačných zmien a pracuje s týmto rozvrhom. 
 * @author MartinaHlinková
 */
public class RozvrhMesiaca implements Comparable<RozvrhMesiaca>{
    private InformacieOMesiaci info;
    private TreeMap<Integer,Rozvrh.Zmeny[]> rozvrh;
    private HashMap<Integer,Integer>riadkyZamestnancov;
    
    /**
     * Konštruktor objektov triedy RozvrhMesiaca, vytvára prázdny mesačný rozvrh podľa informácií
     * mesiaca, zadaných v atribúte.
     * @param info 
     */
    public RozvrhMesiaca(InformacieOMesiaci info){
        this.info = info;
        this.rozvrh = new TreeMap<Integer,Rozvrh.Zmeny[]>();
        this.riadkyZamestnancov = new HashMap<Integer,Integer>();
        int j = 0;
        for(Sablony.Zamestnanec iterator : this.info.getMnozinaZamestnancov().values()){
            Rozvrh.Zmeny[] nove = new Rozvrh.Zmeny[info.getPocetDni()];
            for(int i = 0 ; i< info.getPocetDni(); i++){
                nove[i] = null;
            }
            this.riadkyZamestnancov.put(j, iterator.getIDZamestnanca());   
            rozvrh.put(iterator.getIDZamestnanca(), nove);
            j++;
        }
    }
    
    /**
     * Konštruktor objektov triedy RovrhMesiaca, ktorá va vytvorí nastavením všetkých parametrov
     * @param info  informácie o mesiaci
     * @param rozvrh    rozvrh zmien v mesiaci, čiže mapa s kľúčami identifikačnými číslami zamestnancov
     * a hodnotami poľom zmien v mesiaci
     * @param riadky zadelenie jednotlivých riadkov zamestnancom, čiže mapa s kľúčmi poradia riadkov a hodnotali 
     * identifikačné čísla zamestnancov
     */
    public RozvrhMesiaca(InformacieOMesiaci info,TreeMap<Integer,Rozvrh.Zmeny[]> rozvrh,HashMap<Integer,Integer> riadky){
        this.info = info;
        this.rozvrh = rozvrh;
        this.riadkyZamestnancov = riadky;
    } 
    
    /**
     * Metóda, ktorá dokáže načítať rozvrh z JavaDOM elementu
     * @param element JavaDOM element
     * @return načítaný rozvrh
     */
    public static Rozvrh.RozvrhMesiaca parsujRozvrh(Element element){
        Rozvrh.RozvrhMesiaca navrat = null;
        if(element == null)return null;
        try{
            int rok = Integer.parseInt(element.getAttribute("rok"));
            int pocetDni = Integer.parseInt(element.getAttribute("pocetDni"));
            String stringMesiac = element.getAttribute("mesiac");
            InformacnaStruktura.Mesiac mesiac = null;
            for(InformacnaStruktura.Mesiac iterator: InformacnaStruktura.Mesiac.values()){
                if(iterator.toString().equals(stringMesiac)){
                    mesiac = iterator;
                }
            }
        
            if( rok < 1900 || rok > 9999 || pocetDni < 28 || pocetDni > 31 || mesiac == null)return null;
        // nacitanie charakterov dni
            if(element.getElementsByTagName("CharakterDna").getLength() != 1)return null;
            Node nodeCharakter = element.getElementsByTagName("CharakterDna").item(0);
            InformacnaStruktura.CharakterDna[] charakter = null;
            if (nodeCharakter.getNodeType() == Node.ELEMENT_NODE) {
                Element eCharakter = (Element) nodeCharakter;
                String stringCharakter = eCharakter.getTextContent();
                String charakterDni[] = stringCharakter.split(":");
                if(charakterDni.length != pocetDni+1)
                    return null; 
                else{
                    charakter = new InformacnaStruktura.CharakterDna[pocetDni];
                    for(int i = 1; i < charakterDni.length;i++){
                        if(charakterDni[i].equals(InformacnaStruktura.CharakterDna.PRACOVNY.toString())){
                            charakter[i-1] = InformacnaStruktura.CharakterDna.PRACOVNY;
                        }else if(charakterDni[i].equals(InformacnaStruktura.CharakterDna.VOLNY.toString())){
                            charakter[i-1] = InformacnaStruktura.CharakterDna.VOLNY;
                        }else return null;
                    }
                }
            
            }else return null;
        //nacitanie poctu klientov
            if(element.getElementsByTagName("klientiVDnoch").getLength() != 1)return null;
            Node nodeKlienti = element.getElementsByTagName("klientiVDnoch").item(0);
            Integer[] klienti = null;
            if (nodeKlienti.getNodeType() == Node.ELEMENT_NODE) {
                Element eKlienti = (Element) nodeKlienti;
                String stringKlienti = eKlienti.getTextContent();
                String klientiVDnoch[] = stringKlienti.split(":");
                if(klientiVDnoch.length != pocetDni+1)
                    return null; 
                else{
                    klienti = new Integer[pocetDni];
                    for(int i = 1; i < klientiVDnoch.length;i++){
                        int cislo = Integer.parseInt(klientiVDnoch[i]);
                        if(cislo < 0) return null;
                        klienti[i-1] = cislo;
                    }
                }
            
            }else return null;
        
        // mnozina zamestnancov
        TreeMap<Integer,Sablony.Zamestnanec>mnozinaZamestnancov = new TreeMap<Integer,Sablony.Zamestnanec>();
        HashMap<Integer,Rozvrh.Zmeny[]> rozvrh = new HashMap<Integer,Rozvrh.Zmeny[]>();
        if(element.getElementsByTagName("zamestnanci").getLength() != 1)return null;
        Node nodeZamestnanci = element.getElementsByTagName("zamestnanci").item(0);
        if (nodeZamestnanci.getNodeType() == Node.ELEMENT_NODE){
            NodeList nListZamestnanec = ((Element)nodeZamestnanci).getElementsByTagName("zamestnanec");
            
            for(int i = 0; i< nListZamestnanec.getLength();i++){
                if (nListZamestnanec.item(i).getNodeType() == Node.ELEMENT_NODE){
                    Sablony.Zamestnanec novy = Sablony.Zamestnanec.nacitajZamestnanca(((Element)nListZamestnanec.item(i)));
                    if(novy != null){
                        mnozinaZamestnancov.put(novy.getIDZamestnanca(), novy);
                    }
                }
                
                
            }
            
        }else return null;
        
        // nastavenie zamestnancov
        
        HashMap<Integer,Rozvrh.NastavenieZamestnancaMesiac> nastavenieZamestnancov = new HashMap<Integer,Rozvrh.NastavenieZamestnancaMesiac>();
        TreeMap<Integer,Rozvrh.Zmeny[]> rozvrhZmien = new TreeMap<Integer,Rozvrh.Zmeny[]>();
         if(element.getElementsByTagName("nastavenieZamestnancov").getLength() != 1)return null;
         Node nodeNastavenie = element.getElementsByTagName("nastavenieZamestnancov").item(0);
         if (nodeNastavenie.getNodeType() == Node.ELEMENT_NODE){
             NodeList nListNastavenie = ((Element)nodeNastavenie).getElementsByTagName("zamestnanecInfo");
             
             for(int i = 0; i< nListNastavenie.getLength(); i++){
                      Element elementZamestnanec = ((Element)nListNastavenie.item(i));
                      String stringID = elementZamestnanec.getAttribute("ID");
                      int id = Integer.parseInt(stringID);
                      
                      if(id < 100 && id > 9){
                            Rozvrh.NastavenieZamestnancaMesiac nastavenieZamestnanca = Rozvrh.NastavenieZamestnancaMesiac.nacitajNastavenieZamestnanca(elementZamestnanec);
                            Rozvrh.Zmeny[] zmenyZamestnanca = new Rozvrh.Zmeny[pocetDni];
                            NodeList nListZmeny = elementZamestnanec.getElementsByTagName("zmena");
                            for(int j = 0; j < nListZmeny.getLength();j++){
                                zmenyZamestnanca[j] = null;
                            }
                            for(int j = 0; j < nListZmeny.getLength();j++){
                                
                                if(nListZmeny.item(j).getNodeType() == Node.ELEMENT_NODE){
                                    Element elementZmeny = ((Element) nListZmeny.item(j));
                                    String den = elementZmeny.getAttribute("den");
                                    int intDen = Integer.parseInt(den);
                                    if(intDen > 0 && intDen <= pocetDni){
                                        Zmeny zmena = null;
                                        if(elementZmeny.hasAttribute("standard") == true){
                                            zmena = Rozvrh.StandardnaZmena.nacitajZmenu(elementZmeny);
                                        }else if(elementZmeny.hasAttribute("nastav") == true){
                                            zmena = Rozvrh.ZmenaNastavitelnejDlzky.nacitajZmenu(elementZmeny);
                                        }
                                        if(zmena != null){
                                            zmenyZamestnanca[intDen-1] = zmena;
                                        }
                                    }
                                }
                            }
                            nastavenieZamestnancov.put(id, nastavenieZamestnanca);
                            rozvrhZmien.put(id, zmenyZamestnanca);
                      }
             }
          }else return null;
         if(klienti == null || charakter == null|| nastavenieZamestnancov.size() != mnozinaZamestnancov.size())return null;
         Rozvrh.InformacieOMesiaci noveInfo = new Rozvrh.InformacieOMesiaci(rok,mesiac,pocetDni,klienti,charakter,nastavenieZamestnancov,mnozinaZamestnancov);
         if(rozvrhZmien.size() != mnozinaZamestnancov.size())return null;
         
         HashMap<Integer,Integer>riadky = new HashMap<Integer,Integer>();
         int iter = 0;
         for(Integer iterator:mnozinaZamestnancov.keySet()){
             riadky.put(iter, iterator);
             iter++;
         }
         
         navrat = new Rozvrh.RozvrhMesiaca(noveInfo, rozvrhZmien, riadky);
        
        }catch (Exception e) {
            e.printStackTrace();   
        }
        
        return navrat;
    }
    
    /**
     * Metóda vracajúca mapu rozvrhu
     * @return mapa rozvrhu
     */
    public TreeMap<Integer,Rozvrh.Zmeny[]> getRozvrh(){
        return this.rozvrh;
    }
    
    /**
     * Metóda vracajúca informácie o mesiaci 
     * @return informácie o mesiaci 
     */
    public InformacieOMesiaci getInfo(){
        return this.info;
    }

    @Override
    public int compareTo(RozvrhMesiaca o) {
        if(this.info.getRok() < o.getInfo().getRok()){
            return -1;
        }else if(this.info.getRok() > o.getInfo().getRok()){
            return 1;
        }else
            if(this.info.getMasiac().getPoradieMesiaca() < o.getInfo().getMasiac().getPoradieMesiaca()){
                return -1;
            }else if(this.info.getMasiac().getPoradieMesiaca() > o.getInfo().getMasiac().getPoradieMesiaca()){
                return 1;
            }
            return 0;
        }
    
    /**
     * Metóda, ktorá zmení zmenu v dni zamestnancovi podla koordinátov
     * @param stlpec    poradie stĺpca, v ktorom sa má zmeniť zmena (deň)
     * @param riadok    poradie riadku, v ktorom sa má zmeniť zmena (zamestnanec)
     * @param zmena     typ zmeny na ktorú sa má zmeniť
     * @return  true, pokiaľ sa úspešne zmenila zmena, inak false
     */
    public boolean nastavenieZmenyPodlaKoordinatov(int stlpec, int riadok, Rozvrh.Zmeny zmena){
        int idZamestnanca = this.riadkyZamestnancov.get(riadok);
        if(zmena == null){
            this.rozvrh.get(idZamestnanca)[stlpec] = null;
            return true;
        }
        
        if(RozvrhMesiaca.skotrolujTypZmeny(zmena,this.info.getCharakterDni()[stlpec]) == false){
                    return false;
        }
        this.rozvrh.get(idZamestnanca)[stlpec] = zmena;
       // System.out.println("Zadelena zmena: "+this.getInfo().getMnozinaZamestnancov().get(idZamestnanca).getPriezviskoZamestnanca()+" : "+zmena);
        return true;
              
    }
    
    /**
     * Metóda skontroluje, či danému zamestnancovi v daný deň je možné zadeliť zadaný typ zmeny.
     * @param zmena typ zmeny, ktorý sa kontroluje
     * @param den   deň ktorý sa kontroluje
     * @return true, ak je možné zadeliť zmenu, inak false
     */
    public static boolean skotrolujTypZmeny( Rozvrh.Zmeny zmena,InformacnaStruktura.CharakterDna den){
        if(zmena == null || den == null)return false;
        if(zmena.getClass() == Rozvrh.StandardnaZmena.class){
            Sablony.Funkcia funkcia = ((Rozvrh.StandardnaZmena)zmena).getFunkcia();
            if(funkcia == null){
                
            return false;
            } 
            InformacnaStruktura.TypZmeny typ = ((Rozvrh.StandardnaZmena)zmena).typZmeny;
            
            switch(funkcia){

            case KMENOVY:{
                    if(typ == InformacnaStruktura.TypZmeny.KUCHYNA)return false;
                    if(typ == InformacnaStruktura.TypZmeny.RANNA && den == InformacnaStruktura.CharakterDna.VOLNY)return false;
                    if(typ == InformacnaStruktura.TypZmeny.POOBEDNA && den == InformacnaStruktura.CharakterDna.VOLNY)return false;
                    if(typ == InformacnaStruktura.TypZmeny.NOCNA || typ == InformacnaStruktura.TypZmeny.NOCNA_DLHA)return true;
                    if(typ == InformacnaStruktura.TypZmeny.NOCNA_DLHA && den == InformacnaStruktura.CharakterDna.PRACOVNY)return false;
                    return true;
                    }
            case ASISTENT:{
                    if(typ == InformacnaStruktura.TypZmeny.KUCHYNA)return false;
                    if(typ == InformacnaStruktura.TypZmeny.DENNA)return false;
                    if(typ == InformacnaStruktura.TypZmeny.RANNA && den == InformacnaStruktura.CharakterDna.VOLNY)return false;
                    if(typ == InformacnaStruktura.TypZmeny.POOBEDNA && den == InformacnaStruktura.CharakterDna.VOLNY)return false;
                    if(typ == InformacnaStruktura.TypZmeny.NOCNA && den == InformacnaStruktura.CharakterDna.VOLNY)return false;
                    //if(zmena == InformacnaStruktura.TypZmeny.NOCNA_DLHA && den == InformacnaStruktura.CharakterDna.PRACOVNY)return false;
                    return true;}
            case SKRATENY:{
                    if(typ == InformacnaStruktura.TypZmeny.KUCHYNA && den == InformacnaStruktura.CharakterDna.PRACOVNY)return true;
                    if(typ == InformacnaStruktura.TypZmeny.RANNA && den == InformacnaStruktura.CharakterDna.PRACOVNY)return true;
                    if(typ == InformacnaStruktura.TypZmeny.DOVOLENKA)return true;
                    return false;
                    }
            case KUCHAR:{
                    if(typ == InformacnaStruktura.TypZmeny.DENNA || typ == InformacnaStruktura.TypZmeny.RANNA)return true;
                    if(typ == InformacnaStruktura.TypZmeny.DOVOLENKA)return true;
                    return false;
                    }
                
            }
        }
        //Sablony.Funkcia funkcia = this.info.getMnozinaZamestnancov().get(id).getFunkciaZamestnanca();
        
        
        return true;
    }
    /**
     * Metóda, ktorá vráti zmenu podľa koordinátov v rozvrhu
     * @param stlpec    stĺpec, v ktorom sa nachádza požadovaná zmena
     * @param riadok    riadok, v ktorom sa nachádza požadovaná zmena
     * @return požadovaná zmena
     */
    public Rozvrh.Zmeny getZmenaPodlaKoordinatov(int stlpec, int riadok){
        
        int idZamestnanca = this.riadkyZamestnancov.get(riadok);
        return this.rozvrh.get(idZamestnanca)[stlpec];
        
    }
    
    /**
     * Metóda, ktorá vráti zamestnanca podla zadaného bodu v tabuľke rozvrhu. 
     * @param bod   zadaný bod, podľa ktorého sa hľadá zamestnanec
     * @return  hľadaný zamestnanec
     */
    public Sablony.Zamestnanec getZamestnanecPodlaRiadku(Point bod){
        int riadok = (int)((bod.y-PlatnoRozvrh.DEN_POLE_VYSKA)/PlatnoRozvrh.MENO_POLE_VYSKA);
        int idZamestnanca = this.riadkyZamestnancov.get(riadok);
        return this.info.getMnozinaZamestnancov().get(idZamestnanca);
        
    }
    /**
     * Metóda, ktorá vracia mapu riadkov rozvrhu (v ktorom riadku sa nachádza ktorý zamestnanec ).
     * @return riadky zamestnancov
     */
    public HashMap<Integer,Integer> getRiadkyZamestnancov(){
        return this.riadkyZamestnancov;
    }
    
    private boolean patriDoZmeny(InformacnaStruktura.CasBezDatumu casOd, InformacnaStruktura.CasBezDatumu casDo, InformacnaStruktura.CasBezDatumu skumanyCas){
        if(casOd.after(casDo)){
            if(casOd.equals(skumanyCas) || casDo.equals(skumanyCas)){
                return true;
            }
            if(skumanyCas.equals(new InformacnaStruktura.CasBezDatumu(0, 0)) || skumanyCas.equals(new InformacnaStruktura.CasBezDatumu(23, 59))){
                return true;
            }
            if(skumanyCas.before(casDo))return true;
            if(skumanyCas.after(casOd))return true;
            return false;
        }else{
            if((casOd.before(skumanyCas) && casDo.after(skumanyCas))|| casOd.equals(skumanyCas) || casDo.equals(skumanyCas)){
                return true;
            }else{
                return false;
            }
        }
    }
    
    /**
     * Metóda, ktorá skontroluje všetky pravidlá rozvrhovania.
     * @return Množina textových reťazcov popisujúcich kolízie v rozvrhovaní.
     */
    public HashSet<String> skontrolujRozvrh(){
        HashSet<String> chyby = new HashSet<String>();
        
        chyby.addAll(kontrolaSilnychZamestnancov());
        chyby.addAll(kontrolaZienVZmenach());
        chyby.addAll(kontrolaPravidlaPoNocnej());
        chyby.addAll(kontrolaPravidlaDostatkuZamestnancov());
        chyby.addAll(prepocetOdpracovanychHodin());
        chyby.addAll(kontrolaNepritomnostiZamestnancov());
        return chyby;
    }
    /**
     * Metóda, ktorá prepočíta odpracované hodiny každého zamestnanca a skontroluje,
     * či nadošlo k prekročeniu maximálneho počtu hodín.
     * @return Množina textových reťazcov popisujúcich kolízie v rozvrhovaní.
     */
    public HashSet<String> prepocetOdpracovanychHodin(){
        HashSet<String> navrat = new HashSet<String>();
        
        for(Integer id:this.riadkyZamestnancov.values()){
            int odpracovaneMinuty=0;
            for(Rozvrh.Zmeny zmena: this.rozvrh.get(id)){
                if(zmena != null && zmena.getTypZmeny()!= InformacnaStruktura.TypZmeny.DOVOLENKA){
                    InformacnaStruktura.CasBezDatumu odpracovanyCas = zmena.getOdpracovanyCas();
                    odpracovaneMinuty += (odpracovanyCas.getHodiny()*60+odpracovanyCas.getMinuty());
                }else if(zmena != null && zmena.getTypZmeny()== InformacnaStruktura.TypZmeny.DOVOLENKA){
                    odpracovaneMinuty +=(7*60+30);
                }
            }
            Rozvrh.NastavenieZamestnancaMesiac nastavenie = this.getInfo().getNastavenieZamestnancov().get(id);
            nastavenie.setTentoMesiac(new InformacnaStruktura.CasBezDatumu(odpracovaneMinuty));
            Sablony.Zamestnanec kontrolovanyZamestnanec = this.info.getMnozinaZamestnancov().get(id);
            if(odpracovaneMinuty > this.info.getMaximalnyPocetMinut()){
                navrat.add("Zamestnanec "+ kontrolovanyZamestnanec.getMenoZamestnanca()+" "+
                        kontrolovanyZamestnanec.getPriezviskoZamestnanca()+" prekročil povolený počet hodin na mesiac.");
            }
            if(kontrolovanyZamestnanec.getTypZamestnanca() == Sablony.TypZamestnanca.ZIVNOSTNIK &&
                     odpracovaneMinuty != this.info.getOptimalnyPocetMinut()){
                if(odpracovaneMinuty < this.info.getOptimalnyPocetMinut()){
                    navrat.add("Zamestnanec "+ kontrolovanyZamestnanec.getMenoZamestnanca()+" "+
                        kontrolovanyZamestnanec.getPriezviskoZamestnanca()+" potrebuje ešte doplniť zmeny o trvaní "+
                           (this.info.getOptimalnyPocetMinut()-odpracovaneMinuty)+" minút." );
                }else{
                    navrat.add("Zamestnanec "+ kontrolovanyZamestnanec.getMenoZamestnanca()+" "+
                        kontrolovanyZamestnanec.getPriezviskoZamestnanca()+" prekročil limit o "+
                           (odpracovaneMinuty -this.info.getOptimalnyPocetMinut())+" minút." );
                }
            }
            //Rozvrh.NastavenieZamestnancaMesiac nastavenie =this.getInfo().getNastavenieZamestnancov().get(id);
            
            //nastavenie odpracovanych hodin
            nastavenie.setTentoMesiac(new InformacnaStruktura.CasBezDatumu(odpracovaneMinuty/60, odpracovaneMinuty%60));
            int minuleObdobie = nastavenie.getPrenostMinulehoObdobia().getHodiny()*60+nastavenie.getPrenostMinulehoObdobia().getMinuty();
            if(nastavenie.getTypSaldaMinulost() == TypSalda.NEDOPOCETNE){
                minuleObdobie *= (-1);
            }
            int nadcas = (odpracovaneMinuty+minuleObdobie)-this.info.getOptimalnyPocetMinut();
            //System.out.println("Opt cas "+this.info.getOptimalnyPocetMinut()+" odpracovane minuty "+odpracovaneMinuty + " nadcas "+nadcas);
            //System.out.println("Tento mesiac "+nastavenie.getTentoMesiac());
            //System.out.println("Minulost "+nastavenie.getPrenostMinulehoObdobia()+" "+nastavenie.getTypSaldaMinulost());
            if(nadcas < 0){
                nastavenie.setTypSaldaBuducnost(TypSalda.NEDOPOCETNE);
                nadcas *=(-1);
                int hodiny = nadcas/60;
                int minuty = nadcas%60;
                InformacnaStruktura.CasBezDatumu nedopocetne = new InformacnaStruktura.CasBezDatumu(hodiny,minuty);
                nastavenie.setPrenosBuducnost(nedopocetne);
            }else{
                nastavenie.setTypSaldaBuducnost(TypSalda.NADPOCETNE);
                int hodiny = nadcas/60;
                int minuty = nadcas%60;
                InformacnaStruktura.CasBezDatumu nadpocetne = new InformacnaStruktura.CasBezDatumu(hodiny,minuty);
                nastavenie.setPrenosBuducnost(nadpocetne);
            }
        }
       return navrat; 
    }
    
    /**
     * Metóda, ktorá kontroluje, či sa nezadelili zmeny zamestnancom v ich nastavených neprítomnostiach.
     * @return Množina textových reťazcov popisujúcich kolízie v rozvrhovaní.
     */
    public HashSet<String> kontrolaNepritomnostiZamestnancov(){
        HashSet<String> navrat = new HashSet<String>();
        
        for(Integer id:this.riadkyZamestnancov.values()){
            Sablony.Zamestnanec kontrolovany = this.info.getMnozinaZamestnancov().get(id);
            TreeSet<Sablony.NepritomnostZamestnanca> nepritomnosti = kontrolovany.getNepritomnost();
            
           
            for(Sablony.NepritomnostZamestnanca nepritomnost:nepritomnosti){
                for(int i = 0; i < this.getInfo().getPocetDni();i++){
                    Rozvrh.Zmeny zmena = this.rozvrh.get(id)[i];
                    if(zmena != null){
                    
                        Date datNeprOd = new Date(this.getInfo().getRok()-1900,this.getInfo().getMasiac().getPoradieMesiaca()
                                ,(i+1));
                        datNeprOd.setHours(nepritomnost.getCasOdkedy().getHodiny());
                        datNeprOd.setMinutes(nepritomnost.getCasOdkedy().getMinuty());
                        
                        Date datNeprDo = new Date(this.getInfo().getRok()-1900,this.getInfo().getMasiac().getPoradieMesiaca()
                                ,(i+1));
                        datNeprDo.setHours(nepritomnost.getCasDokedy().getHodiny());
                        datNeprDo.setMinutes(nepritomnost.getCasDokedy().getMinuty());
                        
                        Date datZmenaOd = (Date)datNeprOd.clone();
                        datZmenaOd.setHours(zmena.getCasOd().getHodiny());
                        datZmenaOd.setMinutes(zmena.getCasOd().getMinuty());
                        
                        Date datZmenaDo = (Date)datNeprOd.clone();
                        if(zmena.getTypZmeny() == InformacnaStruktura.TypZmeny.NOCNA ||
                           zmena.getTypZmeny() == InformacnaStruktura.TypZmeny.NOCNA_DLHA ||
                           (zmena.getClass() == Rozvrh.ZmenaNastavitelnejDlzky.class && ((Rozvrh.ZmenaNastavitelnejDlzky)zmena).getTypCasu() == InformacnaStruktura.TypZmeny.NOCNA ))
                        {
                            datZmenaDo.setDate(i+2);
                            datNeprOd.setDate(i+2);
                            datNeprDo.setDate(i+2);
                        }
                        datZmenaDo.setHours(zmena.getCasDo().getHodiny());
                        datZmenaDo.setMinutes(zmena.getCasDo().getMinuty());
                        
                        
                        
                        if(datZmenaOd.getDay() == nepritomnost.getDenNepritomnosti().getPoradie() ||
                           datZmenaDo.getDay() == nepritomnost.getDenNepritomnosti().getPoradie())
                        {
                            
                            if((datZmenaOd.after(datNeprOd) && datZmenaOd.before(datNeprDo)) ||
                           (datNeprDo.after(datZmenaOd) && datNeprDo.before(datZmenaDo)) ||
                           (datNeprOd.after(datZmenaOd) && datNeprOd.before(datZmenaDo)) ||
                           (datZmenaDo.after(datNeprOd) && datZmenaDo.before(datNeprDo)) )
                                {
                                    navrat.add("Porušenie pravidla o nepritomnosti zamestnanca: "+kontrolovany.getMenoZamestnanca()+" "+
                                        kontrolovany.getPriezviskoZamestnanca()+" "+nepritomnost+" v dni cislo "+(i+1));
                                }
                        
                        }
                        
                        
                        
                    }//pre nenulovu zmenu
                }//pre kazdu zmenu
                    
            }//pre kazdu nepritomnost zamestnanca
            
        }// pre kazde id zamestnancov
        
        return navrat;
    }
    
    /**
     * Metóda, ktorá skontroluje, či v nie nočných zmenách je prítomný aspoň jeden silný zamestnanec.
     * @return Množina textových reťazcov popisujúcich kolízie v rozvrhovaní.
     */
    public HashSet<String> kontrolaSilnychZamestnancov(){
        String ranne = "";
        String poobedne = "";
        String denne = "";
        
        for(int i = 1; i<= this.info.getPocetDni();i++){
            if(this.info.getCharakterDni()[i-1] == InformacnaStruktura.CharakterDna.PRACOVNY){
                //Kontrola Rannych zmien
                if(zistiPocetSilnychZamestnancov(i,InformacnaStruktura.TypZmeny.RANNA)== 0){
                    ranne += (i+", ");
                }
                //Kontrola Poobednych zmien
                if(zistiPocetSilnychZamestnancov(i,InformacnaStruktura.TypZmeny.POOBEDNA)== 0){
                    poobedne += (i+", ");
                }
            }else{
                //KOntrola dennych
                if(zistiPocetSilnychZamestnancov(i,InformacnaStruktura.TypZmeny.DENNA)== 0){
                    denne += (i+", ");
                }
            }
        }
        
        HashSet<String> navrat = new HashSet<String>();
        if(ranne.length() > 0){
            ranne = "Tieto dni nemajú v ranných zmenách silného zamestnanca: "+ranne;
            navrat.add(ranne);
        }
        if(poobedne.length() > 0){
            poobedne = "Tieto dni nemajú v poobedných zmenách silného zamestnanca: "+poobedne;
            navrat.add(poobedne);
        }
        if(denne.length() > 0){
            denne = "Tieto dni nemajú v denných zmenách silného zamestnanca: "+denne;
            navrat.add(denne);
        }
        
        return navrat;
    }
    
    /**
     * Metóda, ktorá skontroluje, či v každej zmene je aspoň jedna žena.
     * @return Množina textových reťazcov popisujúcich kolízie v rozvrhovaní.
     */
    public HashSet<String> kontrolaZienVZmenach(){
         String ranne = "";
        String poobedne = "";
        String denne = "";
        String nocne = "";
        
        for(int i = 1; i<= this.info.getPocetDni();i++){
            if(zistiPocetZien(i,InformacnaStruktura.TypZmeny.NOCNA)== 0){
                    nocne += (i+", ");
                }
            if(this.info.getCharakterDni()[i-1] == InformacnaStruktura.CharakterDna.PRACOVNY){
                //Kontrola Rannych zmien
                if(zistiPocetZien(i,InformacnaStruktura.TypZmeny.RANNA)== 0){
                    ranne += (i+", ");
                }
                //Kontrola Poobednych zmien
                if(zistiPocetZien(i,InformacnaStruktura.TypZmeny.POOBEDNA)== 0){
                    poobedne += (i+", ");
                }
            }else{
                //KOntrola dennych
                if(zistiPocetZien(i,InformacnaStruktura.TypZmeny.DENNA)== 0){
                    denne += (i+", ");
                }
            }
        }
        HashSet<String> navrat = new HashSet<String>();
        if(ranne.length() > 0){
            ranne = "Tieto dni nemajú v ranných zmenách ženu: "+ranne;
            navrat.add(ranne);
        }
        if(poobedne.length() > 0){
            poobedne = "Tieto dni nemajú v poobedných zmenách ženu: "+poobedne;
            navrat.add(poobedne);
        }
        if(denne.length() > 0){
            denne = "Tieto dni nemajú v denných zmenách ženu: "+denne;
            navrat.add(denne);
        }
        if(nocne.length() > 0){
            nocne = "Tieto dni nemajú v nočných zmenách ženu: "+nocne;
            navrat.add(nocne);
        }
        
        return navrat;
    
    }
    
    /**
     * Metóda, ktorá kontroluje, či zamestnanci po nočnej zmene majú deň osobného voľna
     * @return Množina textových reťazcov popisujúcich kolízie v rozvrhovaní.
     */
    public HashSet<String> kontrolaPravidlaPoNocnej(){
        HashSet<String> navrat = new HashSet<String>();
        for(Integer cisloRiadku: this.riadkyZamestnancov.keySet()){
            Sablony.Zamestnanec kontrolovanyZamestnanec = this.getInfo().getMnozinaZamestnancov().get(this.riadkyZamestnancov.get(cisloRiadku));
            for(int i = 0; i< this.getInfo().getPocetDni(); i++ ){
                Rozvrh.Zmeny kontrolovanaZmena = this.rozvrh.get(kontrolovanyZamestnanec.getIDZamestnanca())[i];
                if(kontrolovanaZmena != null){
                    if(kontrolovanaZmena.getTypZmeny() == InformacnaStruktura.TypZmeny.NOCNA ||
                        kontrolovanaZmena.getTypZmeny() == InformacnaStruktura.TypZmeny.NOCNA_DLHA ||(
                            kontrolovanaZmena.getClass() == Rozvrh.ZmenaNastavitelnejDlzky.class && 
                            ((Rozvrh.ZmenaNastavitelnejDlzky)kontrolovanaZmena).getTypCasu() == InformacnaStruktura.TypZmeny.NOCNA
                            )){
                    
                    
                            if( (i+1) < this.getInfo().getPocetDni() ){
                            Rozvrh.Zmeny dalsiaZmena = this.rozvrh.get(kontrolovanyZamestnanec.getIDZamestnanca())[i+1];
                                if(dalsiaZmena != null && dalsiaZmena.getTypZmeny() != InformacnaStruktura.TypZmeny.DOVOLENKA){
                                    navrat.add("Porušenie pravidla o voľne po nočnej zmene u zamestanca "+kontrolovanyZamestnanec.getMenoZamestnanca()+
                                        " "+kontrolovanyZamestnanec.getPriezviskoZamestnanca()+" v dni číslo "+ (i+2));
                                }
                            }
                    }
                }
                
            }
        
        }
        return navrat;
    }
    
    /**
     * Metóda, ktorá skontroluje, či na zmenách je pridelených dostatok zamestnancov.
     * @return Množina textových reťazcov popisujúcich kolízie v rozvrhovaní.
     */
    public HashSet<String> kontrolaPravidlaDostatkuZamestnancov(){
        HashSet<String> navrat = new HashSet<String>();
        String rannaString = "";
        String poobednaString = "";
        String nocnaString = "";
        String dennaString = "";
        for(int i = 0 ; i< this.getInfo().getPocetDni();i++){
            int koeficientKlientov = this.getInfo().getKlientiVDnoch()[i];
            if(this.getInfo().getCharakterDni()[i] != null){
                if(this.getInfo().getCharakterDni()[i] == InformacnaStruktura.CharakterDna.PRACOVNY){
                    int ranna=0;
                    int poobedna = 0;
                    int nocna = 0;
                
                    for(Integer id:this.riadkyZamestnancov.values()){
                        Rozvrh.Zmeny kontrolovanaZmena = this.rozvrh.get(id)[i];
                        Sablony.Zamestnanec kontrolovanyZamestnanec = this.getInfo().getMnozinaZamestnancov().get(id);
                        if(kontrolovanaZmena !=null && kontrolovanyZamestnanec.getFunkciaZamestnanca() != Sablony.Funkcia.KUCHAR){
                            InformacnaStruktura.CasBezDatumu casOd = kontrolovanaZmena.getCasOd();
                            InformacnaStruktura.CasBezDatumu casDo = kontrolovanaZmena.getCasDo();
                            if(patriDoZmeny(casOd, casDo, new InformacnaStruktura.CasBezDatumu(9,0)) == true){
                                ranna++;
                            }else if(patriDoZmeny(casOd, casDo, new InformacnaStruktura.CasBezDatumu(16,0)) == true){
                                poobedna++;
                            }else if(patriDoZmeny(casOd, casDo, new InformacnaStruktura.CasBezDatumu(1,0)) == true){
                                nocna++;
                            }
                        }
                    }
                
                    if(ranna<koeficientKlientov) rannaString += " "+(i+1)+"("+(koeficientKlientov-ranna)+"z.),";
                    if(poobedna<koeficientKlientov) poobednaString += " "+(i+1)+"("+(koeficientKlientov-poobedna)+"z.),";
                    if(koeficientKlientov > 2 && nocna<2) nocnaString += " "+(i+1)+"("+(2-nocna)+"z.),";
                    else if(koeficientKlientov <= 2 && nocna<1) nocnaString += " "+(i+1)+"("+(1-nocna)+"z.),";
                }else{
                    int denna=0;
                    int nocna=0;
                
                    for(Integer id:this.riadkyZamestnancov.values()){
                        Rozvrh.Zmeny kontrolovanaZmena = this.rozvrh.get(id)[i];
                        if(kontrolovanaZmena != null){
                            InformacnaStruktura.CasBezDatumu casOd = kontrolovanaZmena.getCasOd();
                            InformacnaStruktura.CasBezDatumu casDo = kontrolovanaZmena.getCasDo();
                            if(patriDoZmeny(casOd, casDo, new InformacnaStruktura.CasBezDatumu(12,0)) == true){
                                denna++;
                            }else if(patriDoZmeny(casOd, casDo, new InformacnaStruktura.CasBezDatumu(1,0)) == true){
                                nocna++;
                            }
                        } 
                    }
                    if(denna<koeficientKlientov) dennaString += " "+(i+1)+"("+(koeficientKlientov-denna)+"z.),";
                   if(koeficientKlientov > 2 && nocna<2) nocnaString += " "+(i+1)+"("+(2-nocna)+"z.),";
                    else if(koeficientKlientov <= 2 && nocna<1) nocnaString += " "+(i+1)+"("+(1-nocna)+"z.),";
                }
            }
        }
        if(rannaString.length() != 0) navrat.add(("Porušenie pravidla počtu zamestnancov na rannej zmene pre dni:"+rannaString));
        if(poobednaString.length() != 0) navrat.add(("Porušenie pravidla počtu zamestnancov na poobednej zmene pre dni:"+poobednaString));
        if(nocnaString.length() != 0) navrat.add(("Porušenie pravidla počtu zamestnancov na nočnej zmene pre dni:"+nocnaString));
        if(dennaString.length() != 0) navrat.add(("Porušenie pravidla počtu zamestnancov na dennej zmene pre dni:"+dennaString));
        return navrat;
    }
    
    /**
     * Metóda, ktorá v zadaný deň v zadanú zmenu vypočíta počet silných zamestnancov.
     * @param den   deň, v tkorom sa počítajú zamestnanci
     * @param zmena typ zmeny, v ktorej sa počítajú zamestnanci
     * @return počet prítomných silných zamestnancov na zmene
     */
    public int zistiPocetSilnychZamestnancov(int den, InformacnaStruktura.TypZmeny zmena){
        if(den<=0 || den > this.info.getPocetDni() || zmena == null) return -1;
        InformacnaStruktura.CasBezDatumu casMerania;
        switch(zmena){
            case RANNA:{
                casMerania = new InformacnaStruktura.CasBezDatumu(9,0);
                break;
            }
            case POOBEDNA:{
                casMerania = new InformacnaStruktura.CasBezDatumu(16,0);
                break;
            }
            case DENNA:{
                casMerania = new InformacnaStruktura.CasBezDatumu(12, 0);
                break;
            }
         
          
            default:
                return -1;        
        }
        int pocetSilnych = 0;
        for(Integer riadok : this.riadkyZamestnancov.keySet() ){
            
            //kontrola, ci s nejedna o Kuchara a je silny
            
            Sablony.Zamestnanec kontrolovanyZamestnanec = this.info.getMnozinaZamestnancov().get(this.riadkyZamestnancov.get(riadok));
            if(kontrolovanyZamestnanec.getFunkciaZamestnanca() != Sablony.Funkcia.KUCHAR && kontrolovanyZamestnanec.getSilaZamestnanca() == Sablony.SiloveUlohy.SILNY){
                
                //kontrola silneho
                Rozvrh.Zmeny kontrolovanaZmena = this.rozvrh.get(this.riadkyZamestnancov.get(riadok))[den-1];
                if(kontrolovanaZmena != null ){
                    if(kontrolovanaZmena.getTypZmeny() != InformacnaStruktura.TypZmeny.KUCHYNA && kontrolovanaZmena.getTypZmeny() != InformacnaStruktura.TypZmeny.DOVOLENKA ){
                        InformacnaStruktura.CasBezDatumu casOd = kontrolovanaZmena.getCasOd();
                        InformacnaStruktura.CasBezDatumu casDo = kontrolovanaZmena.getCasDo();
                        
                        if(patriDoZmeny(casOd,casDo,casMerania)== true){
                            pocetSilnych++;
                        }
                    }
                }
            }
            
            
           
        }
        
        return pocetSilnych;
    }
    
    /**
     * Metóda, ktorá v zadaný deň v zadanú zmenu vypočíta počet žien.
     * @param den   deň, v tkorom sa počítajú zamestnanci
     * @param zmena typ zmeny, v ktorej sa počítajú zamestnanci
     * @return počet prítomných žien na zmene
     */
     public int zistiPocetZien(int den, InformacnaStruktura.TypZmeny zmena){
         if(den<=0 || den > this.info.getPocetDni() || zmena == null) return -1;
        InformacnaStruktura.CasBezDatumu casMerania;
        switch(zmena){
            case RANNA:{
                casMerania = new InformacnaStruktura.CasBezDatumu(9,0);
                break;
            }
            case POOBEDNA:{
                casMerania = new InformacnaStruktura.CasBezDatumu(16,0);
                break;
            }
            case DENNA:{
                casMerania = new InformacnaStruktura.CasBezDatumu(12, 0);
                break;
            }
            case NOCNA:
            case NOCNA_DLHA:{
                casMerania = new InformacnaStruktura.CasBezDatumu(1, 0);
                break;
            }
            default:
                return -1;        
        }
        int pocetZien = 0;
        for(Integer riadok : this.riadkyZamestnancov.keySet() ){
            //kontrola, ci s nejedna o Kuchara a je zena
            Sablony.Zamestnanec kontrolovanyZamestnanec = this.info.getMnozinaZamestnancov().get(this.riadkyZamestnancov.get(riadok));
            if(kontrolovanyZamestnanec.getFunkciaZamestnanca() != Sablony.Funkcia.KUCHAR && kontrolovanyZamestnanec.getPohlavieZamestnanca() == Sablony.Pohlavie.ZENA){
                //kontrola zmeny zeny
                
                Rozvrh.Zmeny kontrolovanaZmena = this.rozvrh.get(this.riadkyZamestnancov.get(riadok))[den-1];
                if(kontrolovanaZmena != null ){
                    if(kontrolovanaZmena.getTypZmeny() != InformacnaStruktura.TypZmeny.KUCHYNA && kontrolovanaZmena.getTypZmeny() != InformacnaStruktura.TypZmeny.DOVOLENKA ){
                        InformacnaStruktura.CasBezDatumu casOd = kontrolovanaZmena.getCasOd();
                        InformacnaStruktura.CasBezDatumu casDo = kontrolovanaZmena.getCasDo();
                        
                        if(patriDoZmeny(casOd,casDo,casMerania)== true){
                            pocetZien++;
                        }
                    }
                
                }
                
            }
             
        }
        return pocetZien;
     }
     
     
}
